<!DOCTYPE HTML>
<html lang="zh">
<head>
<title>InputHook - 语法 &amp; 使用 | AutoHotkey v2</title>
<meta name="description" content="The InputHook function creates an object which can be used to collect or intercept keyboard input." />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
</head>
<body>

<h1>InputHook</h1>

<p>创建一个对象, 该对象可用于收集或拦截键盘输入.</p>

<pre class="Syntax">InputHook := <span class="func">InputHook</span>(<span class="optional">Options, EndKeys, MatchList</span>)</pre>
<h2 id="Parameters">参数</h2>
<dl>

  <dt>Options</dt>
  <dd>
    <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
    <p><u>由零个或多个下列字母组成的字符串(可任意顺序, 中间可选空格):</u></p>
    <p id="option-b"><strong>B</strong>: 设置 <a href="#BackspaceIsUndo">BackspaceIsUndo</a> 为 false, 这会导致 <kbd>Backspace</kbd> 被忽略.</p>
    <p id="option-c"><strong>C</strong>: 设置 <a href="#CaseSensitive">CaseSensitive</a> 为 true, 使 <em>MatchList</em> 区分大小写.</p>
    <p id="option-i"><strong>I</strong>: 设置 <a href="#MinSendLevel">MinSendLevel</a> 为 1 或给定值, 使任何<a href="SendLevel.htm">输入级别</a>低于该值的输入被忽略. 例如, <code>I2</code> 将忽略级别为 0(默认值) 或 1 的任何输入, 但将捕获级别为 2 的输入.</p>
    <p id="option-l"><strong>L</strong>: 长度限制(例如 <code>L5</code>). 输入的最大允许长度. 当文本达到这个长度时, 输入被终止, EndReason 被设置为单词 Max(除非文本匹配 <em>MatchList</em> 中的一个短语, 在这种情况下 EndReason 被设置为单词 Match). 如果未指定, 则长度限制为 1023.</p>
    <p>指定 <code>L0</code> 禁用文本的收集和长度限制, 但并不影响按键生成的文本的统计(请参阅 <a href="#VisibleText">VisibleText</a>). 这可以与 <a href="#OnChar">OnChar</a>, <a href="#OnKeyDown">OnKeyDown</a>, <a href="#KeyOpt">KeyOpt</a> 或 <em><a href="#EndKeys">EndKeys</a></em> 组合使用.</p>
    <p id="option-m"><strong>M</strong>: 将修饰键击对应于真正的 ASCII 字符, 识别并转录修饰键击(如 <kbd>Ctrl</kbd>+<kbd>A</kbd> 到 <kbd>Ctrl</kbd>+<kbd>Z</kbd>). 参考这个例子, 它识别 <kbd>Ctrl</kbd>+<kbd>C</kbd>:</p>
    <pre>CtrlC := Chr(3) <em>; 将 Ctrl-C 对应的字符存储在 CtrlC 变量中.</em>
ih := InputHook("L1 M")
ih.Start()
ih.Wait()
if (ih.Input = CtrlC)
    MsgBox "You pressed Control-C."</pre>
    <p class="note"><strong>注意</strong>: 字符 <kbd>Ctrl</kbd>+<kbd>A</kbd> 到 <kbd>Ctrl</kbd>+<kbd>Z</kbd> 对应于 <a href="Chr.htm">Chr(1)</a> 到 <a href="Chr.htm">Chr(26)</a>. 此外, <strong>M</strong> 选项可能会导致某些键盘快捷键(如 <kbd>Ctrl</kbd>+<kbd>&larr;</kbd>) 在输入正在进行时出现异常.</p>
    <p id="option-t"><strong>T</strong>: 设置 <a href="#Timeout">Timeout</a> (例如 <code>T3</code> 或 <code>T2.5</code>).</p>
    <p id="vis"><strong>V</strong>: 设置 <a href="#VisibleText">VisibleText</a> 和 <a href="#VisibleNonText">VisibleNonText</a> 为 true. 通常, 用户的输入被阻止(对系统隐藏). 使用此选项可将用户的击键发送到活动窗口.</p>
    <p id="asterisk"><strong>*</strong>: 通配符. 设置 <a href="#FindAnywhere">FindAnywhere</a> 为 true, 允许在用户键入的任何位置找到匹配项.</p>
    <p id="E"><strong>E</strong>: 按字符代码而不是键码处理单字符结束键.  如果活动窗口的键盘布局与脚本的键盘布局不同, 则可以提供更一致的结果. 它还可以防止实际上不会产生给定结束字符的键组合结束 Input(输入); 例如, 如果 <code>@</code> 是结束键, 则在美式键盘中 <kbd>Shift</kbd>+<kbd>2</kbd> 将触发它, 但 <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>2</kbd> 不会触发(在使用 E 选项时). 如果还使用 <strong>C</strong> 选项, 则结束字符区分大小写.</p>
  </dd>

  <dt id="EndKeys">EndKeys</dt>
  <dd>
    <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
    <p>一个由零个或多个按键组成的列表, 其中任何一个键在按下时终止输入(结束键本身不会写入输入缓冲). 当 Input 以这种方式终止时, EndReason 设置为单词 EndKey, <a href="#EndKey">EndKey</a> 属性设置为键的名称.</p>
    <p><em>EndKeys</em> 列表使用类似于 <a href="Send.htm">Send</a> 函数的格式. 例如, 指定 <code>{Enter}.{Esc}</code> 将使 <kbd>Enter</kbd>, <kbd>.</kbd> 或 <kbd>Esc</kbd> 任一一个都能终止 Input. 使用大括号本身作为结束键, 指定 <code>{{}</code> 和/或 <code>{}}</code>.</p>
    <p>要使用 <kbd>Ctrl</kbd>, <kbd>Alt</kbd> 或 <kbd>Shift</kbd> 作为结束键, 请指定键的左和/或右的版本, 而不是中性版本. 例如, 指定 <code>{LControl}{RControl}</code> 而不是 <code>{Control}</code>.</p>
    <p>尽管不支持诸如 <kbd>Alt</kbd>+<kbd>C</kbd>(!c) 这样的修饰键, 而非-字母数字字符(如 <code>?!:@&amp;{}</code>) 默认情况下需要 Shift 按键按下与否, 取决于字符的正常输入方式. 如果有 <strong>E</strong> 选项, 则将单个字符键名解释为字符, 在这种情况下, 修饰符键必须处于正确的状态才能生成该字符. 当同时使用 <strong>E</strong> 和 <strong>M</strong> 选项时, 通过在 <em>EndKeys</em> 中包括相应的 ASCII 控制字符来支持 <kbd>Ctrl</kbd>+<kbd>A</kbd> 到 <kbd>Ctrl</kbd>+<kbd>Z</kbd>.</p>
    <p>还可以指定明确的虚拟按键代码, 例如 <code>{vkFF}</code> 或 <code>{sc001}</code>. 这在键没有名称且按下时不产生可见字符的罕见情况下非常有用. 它的虚拟键码可以通过<a href="../KeyList.htm#SpecialKeys">按键列表页面</a>底部的步骤来确定.</p>
  </dd>

  <dt id="MatchList">MatchList</dt>
  <dd>
    <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
    <p>以逗号分隔的关键词列表, 其中任何一个都将导致终止输入(在这种情况下, EndReason 将被设置为单词 Match). 用户输入的内容必须完全匹配匹配列表中的某个词组(除非有 <a href="#asterisk">* 选项</a>). 此外, <strong>分隔符逗号周围的任何空格或制表符都是有意义的</strong>, 这意味着它们是匹配字符串的一部分. 例如, 如果 <em>MatchList</em> 为 <code>ABC , XYZ</code>, 则用户必须在 ABC 之后或 XYZ 之前键入空格以形成匹配.</p>
    <p>两个连续的逗号产生单个原义逗号. 例如, 后面的匹配列表会在 string1 的末尾产生单个原义逗号: <code>string1,,,string2</code>. 类似的, 后面的匹配列表仅包含其中有一个原义逗号的单个项目: <code>single,,item</code>.</p>
    <p>因为 <em>MatchList</em> 中的项目不被视为单独的参数, 所以列表可以完全包含在一个变量中. 事实上, 如果此列表的长度超过 16383, 那么列表的全部或部分必须包含在变量中, 因为这个长度是任何脚本行的最大长度. 例如, <em>MatchList</em> 可能由 <code>List1 "," List2 "," List3</code> 组成 -- 其中每个变量都包含匹配词组的子列表.</p>
  </dd>

</dl>

<h2 id="stack">Input 堆栈</h2>
<p>任何数量的 InputHook 对象都可以在任何时候创建和进行, 但是它们启动的顺序会影响 Input 的收集方式.</p>
<p>当每个 Input 开始时(通过 <a href="#Start">Start</a> 方法), 它被推到堆栈的顶部, 只有当 Input 终止时才从堆栈中删除. 键盘事件按最近开始到最早的顺序传递给每个输入. 如果一个输入抑制了一个给定的键盘事件, 那么它就不会再向下传递.</p>
<p>如果击键的<a href="SendLevel.htm">发送级别</a>低于 InputHook 的 <a href="#MinSendLevel">MinSendLevel</a>, 则忽略 <a href="Send.htm">Sent</a> 的击键. 在这种情况下, 击键仍然可以由堆栈中较低的输入来处理.</p>
<p>多个 InputHook 都可以与 <a href="#MinSendLevel">MinSendLevel</a> 一起使用, 以分别收集发送的击键和实际击键.</p>

<h2 id="object">InputHook 对象</h2>
<p>InputHook 函数返回一个 InputHook 对象, 该对象具有以下方法和属性.</p>
<ul class="indent">
  <li><a href="#Methods">方法</a>:
    <ul>
      <li><a href="#KeyOpt">KeyOpt</a>: 设置按键或按键列表的选项.</li>
      <li><a href="#Start">Start</a>: 启动收集输入.</li>
      <li><a href="#Stop">Stop</a>: 终止 Input 并将 EndReason 设置为单词 Stopped.</li>
      <li><a href="#Wait">Wait</a>: 等待, 直到 Input 终止(InProgress 为 false).</li>
   </ul>
  </li>
 <li><a href="#General_Properties">常规属性</a>:
   <ul>
  <li><a href="#EndKey">EndKey</a>: 返回终止 Input 而按下的<a href="#EndKeys">结束建</a>的名称.</li>
  <li><a href="#EndMods">EndMods</a>: 返回在 Input 终止时逻辑上是按下的修饰符键的字符串.</li>
  <li><a href="#EndReason">EndReason</a>: 返回 <a href="#EndReasons">EndReason 字符串</a>, 该字符串表明了 Input 是如何终止的.</li>
  <li><a href="#InProgress">InProgress</a>: 如果输入正在进行, 则返回 true, 否则返回 false.</li>
  <li><a href="#Input">Input</a>: 返回自上次 Input 启动以来收集的任何文本.</li>
  <li><a href="#Match">Match</a>: 返回导致 Input 终止的 <em>MatchList</em> 项目.</li>
  <li><a href="#OnEnd">OnEnd</a>: 检索或设置在 Input 终止时调用的<a href="../misc/Functor.htm">函数对象</a>.</li>
  <li><a href="#OnChar">OnChar</a>: 检索或设置<a href="../misc/Functor.htm">函数对象</a>, 该函数对象将在字符添加到输入缓冲后调用.</li>
  <li><a href="#OnKeyDown">OnKeyDown</a>: 检索或设置<a href="../misc/Functor.htm">函数对象</a>, 该函数对象将在按下启用通知的按键时调用.</li>
  <li><a href="#OnKeyUp">OnKeyUp</a>: 检索或设置<a href="../misc/Functor.htm">函数对象</a>, 该函数对象将在释放启用通知按键时被调用.</li>
</ul>
  </li>
  <li><a href="#Option_Properties">选项属性</a>:
    <ul>
  <li><a href="#BackspaceIsUndo">BackspaceIsUndo</a>: 控制 <kbd>Backspace</kbd> 是否从输入缓冲的末尾删除最近按下的字符.</li>
  <li><a href="#CaseSensitive">CaseSensitive</a>: 控制 <em>MatchList</em> 是否区分大小写.</li>
  <li><a href="#FindAnywhere">FindAnywhere</a>: 控制每个匹配项是否可以是输入文本的子字符串.</li>
  <li><a href="#MinSendLevel">MinSendLevel</a>: 检索或设置要收集的输入的最小<a href="SendLevel.htm">发送级别</a>.</li>
  <li><a href="#NotifyNonText">NotifyNonText</a>: 控制当按下非文本键时是否调用 <a href="#OnKeyDown">OnKeyDown</a> 和 <a href="#OnKeyUp">OnKeyUp</a> 回调.</li>
  <li><a href="#Timeout">Timeout</a>: 检索或设置超时值(以秒为单位).</li>
  <li><a href="#VisibleNonText">VisibleNonText</a>: 控制不产生文本的键或键组合是否可见(不阻止).</li>
  <li><a href="#VisibleText">VisibleText</a>: 控制产生文本的键或键组合是否可见(不阻止).</li>
    </ul>
  </li>
</ul>

<h3 id="Methods">方法</h3>
<div class="methodShort" id="KeyOpt"><h3>KeyOpt</h3>
<p>设置按键或按键列表的选项.</p>
<pre class="Syntax">InputHook.<span class="func">KeyOpt</span>(Keys, KeyOptions)</pre>
<dl>
  <dt>Keys</dt>
  <dd>
  <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
  <p>按键列表. 大括号用于括起按键名称, 虚拟键码或扫描码, 类似于 <a href="Send.htm">Send</a> 函数. 例如, <code>{Enter}.{{}</code> 将应用于 <kbd>Enter</kbd>, <kbd>.</kbd> 和 <kbd>{</kbd>. 按名称, 按 <code>{vkNN}</code> 或按 <code>{scNNN}</code> 指定按键可能会产生三种不同的结果; 有关详情, 请参阅下文.</p>
  <p id="all-keys">单独指定字符串 <code>{All}</code>(不区分大小写) 以便将 <em>KeyOptions</em> 应用于所有 VK 和所有 SC. 然后可以再次调用 KeyOpt 从特定按键中删除选项.</p></dd>
  <dt>KeyOptions</dt>
  <dd>
  <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
  <p>下列单字符选项中的一个或多个(空格和制表符).</p>
  <p id="KeyOpt-minus"><strong>-</strong>(减号): 移除 <code>-</code> 后面的任何选项, 直到下一个 <code>+</code>.</p>
  <p id="KeyOpt-plus"><strong>+</strong>(加号): 取消任何先前的 <code>-</code>, 否则无效.</p>
  <p id="KeyOpt-e"><strong>E</strong>: 结束键. 如果启用, 则按下键终止 Input, 将 <a href="#EndReason">EndReason</a> 设置为单词 EndKey, 将 <a href="#EndKey">EndKey</a> 属性设置为键的标准名称. 与 <em>EndKeys</em> 参数不同, Shift 键的状态将被忽略. 例如, <code>@</code> 和 <code>2</code> 在美式键盘布局中都相当于 <code>{vk32}</code>.</p>
  <p id="KeyOpt-i"><strong>I</strong>: 忽略文本. 通常由该键生成的任何文本都将被忽略, 并且该键被视为非文本键(请参阅 <a href="#VisibleNonText">VisibleNonText</a>). 如果键通常不产生文本, 则没有效果.</p>
  <p id="KeyOpt-n"><strong>N</strong>: 通知. 在每次按下键时调用 <a href="#OnKeyDown">OnKeyDown</a> 和 <a href="#OnKeyUp">OnKeyUp</a> 回调.</p>
  <p id="KeyOpt-s"><strong>S</strong>: 处理它后抑制(阻止) 按键. 这将覆盖 <a href="#VisibleText">VisibleText</a> 或 <a href="#VisibleNonText">VisibleNonText</a> 直到使用 <code>-S</code>. <code>+S</code> 意味着 <code>-V</code>.</p>
  <p id="KeyOpt-v"><strong>V</strong>: 可见. 防止键按被抑制(阻止). 这将覆盖 <a href="#VisibleText">VisibleText</a> 或 <a href="#VisibleNonText">VisibleNonText</a> 直到使用 <code>-V</code>. <code>+V</code> 意味着 <code>-S</code>.</p>
  </dd>
</dl>
<p id="KeyOpt-remarks">选项可以通过虚拟键码和扫描码来设置, 并且是累加的.</p>
<p>当按名称指定一个键时, 选项通过 VK 或 SC 来设置. 如果两个物理键共享相同的 VK, 但 SC 不同(如 <kbd>Up</kbd> 和 <kbd>NumpadUp</kbd>), 则由 SC 处理. 相反, 如果使用 VK 码, 则它将应用于产生该 VK 的任何物理键(这可能会随着时间的推移而变化, 这取决于活动键盘布局).</p>
<p>通过 VK 码删除选项不会影响 SC 设置的任何选项, 反之亦然. 但是, 当按键名删除一个选项并且该名称由 VK 处理时, 对应的 SC 也会删除该选项(根据脚本的键盘布局). 这允许在对<a href="#all-keys">所有按键</a>应用一个选项后按名称排除按键.</p>
<p>如果通过 VK 设置 <code>+V</code>, 而通过 SC 设置 <code>+S</code>(反之亦然), 则 <code>+V</code> 优先.</p>
</div>

<div class="methodShort" id="Start"><h3>Start</h3>
<p>启动收集输入.</p>
<pre class="Syntax">InputHook.<span class="func">Start</span>()</pre>
<p>如果 Input 已经在进行中, 则没有效果.</p>
<p>新启动的 Input 放在 <a href="#stack">InputHook 堆栈</a>的顶部, 这允许它覆盖任何先前启动的 Input.</p>
<p>此方法安装<a href="InstallKeybdHook.htm">键盘钩子</a>(如果还没有安装).</p>
</div>

<div class="methodShort" id="Stop"><h3>Stop</h3>
<p>终止 Input 并将 <a href="#EndReason">EndReason</a> 设置为单词 Stopped.</p>
<pre class="Syntax">InputHook.<span class="func">Stop</span>()</pre>
<p>如果 Input 不在进行中, 则没有效果.</p>
</div>

<div class="methodShort" id="Wait"><h3>Wait</h3>
<p>等待, 直到 Input 终止(<a href="#InProgress">InProgress</a> 为 false).</p>
<pre class="Syntax">InputHook.<span class="func">Wait</span>(<span class="optional">MaxTime</span>)</pre>
<dl>
  <dt>MaxTime</dt>
  <dd>
  <p>类型: <a href="../Concepts.htm#numbers">浮点数</a></p>
  <p>等待的最大秒数. 如果 Input 在 <em>MaxTime</em> 秒后仍在进行中, 则该方法返回且不终止 Input.</p></dd>
</dl>
<p>返回 <a href="#EndReason">EndReason</a>.</p>

</div>

<h3 id="General_Properties">常规属性</h3>
<div class="methodShort" id="EndKey"><h3>EndKey</h3>
<p>返回<a href="#EndKeys">结束键</a>的名称, 按下结束键以终止 Input.</p>
<pre class="Syntax">KeyName := InputHook.EndKey</pre>
<p>注意, EndKey 返回按键的 "标准" 名称, 而不管它在 <em>EndKeys</em> 中是如何编写的. 例如, <code>{Esc}</code> 和 <code>{vk1B}</code> 都产生 <code>Escape</code>. <a href="GetKeyName.htm">GetKeyName</a> 可用于检索标准名称.</p>
<p>如果使用 <a href="#E">E 选项</a>, EndKey 返回输入的实际字符(如果合适). 否则, 键名将根据脚本的活动键盘布局来确定.</p>
<p>如果 <a href="#EndReason">EndReason</a> 不是 "EndKey", EndKey 返回一个空字符串.</p>
</div>

<div class="methodShort" id="EndMods"><h3>EndMods</h3>
<p>返回在 Input 终止时逻辑上按下的修饰符的字符串.</p>
<pre class="Syntax">Mods := InputHook.EndMods</pre>
<p>如果所有修饰符在逻辑上都是按下的, 则完整的字符串为:</p>
<pre>&lt;^&gt;^&lt;!&gt;!&lt;+&gt;+&lt;#&gt;#</pre>
<p>这些修饰符与<a href="../Hotkeys.htm">热键</a>的具有相同的含义. 每个修饰符总是用 &lt;(左) 或 &gt;(右) 限定. 对应的键名是: LCtrl, RCtrl, LAlt, RAlt, LShift, RShift, LWin, RWin.</p>
<p><a href="InStr.htm">InStr</a> 可以用来检查给定的修饰符(如 <code>&gt;!</code> 或 <code>^</code>) 是否存在的. 下面的行可以用来将 <em>Mods</em> 转换成中性修饰符的字符串, 如 <code>^!+#</code>:</p>
<pre>Mods := RegExReplace(Mods, "[&lt;&gt;](.)(?:&gt;\1)?", "$1")</pre>
<p>由于这是瞬间发生的, 此属性可能比 <a href="GetKeyState.htm">GetKeyState</a> 更可靠, 即使在 Input 终止后立即调用 GetKeyState, 或者在 <a href="#OnEnd">OnEnd</a> 回调中.</p>
</div>

<div class="methodShort" id="EndReason"><h3>EndReason</h3>
<p>返回 <a href="#EndReasons">EndReason 字符串</a>, 该字符串表明了 Input 是如何终止的.</p>
<pre class="Syntax">Reason := InputHook.EndReason</pre>
<p>如果 Input 正在进行, 则返回空字符串.</p>
</div>

<div class="methodShort" id="InProgress"><h3>InProgress</h3>
<p>如果输入正在进行, 返回 true, 否则返回 false.</p>
<pre class="Syntax">Boolean := InputHook.InProgress</pre>
</div>

<div class="methodShort" id="Input"><h3>Input</h3>
<p>返回自上次 Input 启动以来收集的任何文本.</p>
<pre class="Syntax">String := InputHook.Input</pre>
<p>此属性可在输入进行中或输入结束后使用.</p>
</div>

<div class="methodShort" id="Match"><h3>Match</h3>
<p>返回导致 Input 终止的 <em><a href="#MatchList">MatchList</a></em> 项目.</p>
<pre class="Syntax">String := InputHook.Match</pre>
<p><strong>返回</strong>匹配项及其原始大小写, 如果省略了 <strong>C</strong> 选项, 则返回的大小写可能与用户键入的大小写不同. 如果 <a href="#EndReason">EndReason</a> 不是 "Match", 则返回空字符串.</p>
</div>

<div class="methodShort" id="OnEnd"><h3>OnEnd</h3>
<p>检索或设置在 Input 终止时调用的<a href="../misc/Functor.htm">函数对象</a>.</p>
<pre class="Syntax">MyFunc := InputHook.OnEnd</pre>
<pre class="Syntax">InputHook.OnEnd := MyFunc</pre>
<p>类型: <a href="../misc/Functor.htm">函数对象</a>或<a href="../Concepts.htm#nothing">空字符串</a>. 默认值: 空字符串.</p>
<p>该函数传递一个参数: 对 InputHook 对象的引用.</p>
<p>该函数作为一个新<a href="../misc/Threads.htm">线程</a>被调用, 因此使用 <a href="SendMode.htm">SendMode</a> 和 <a href="DetectHiddenWindows.htm">DetectHiddenWindows</a> 等设置的默认值重新开始.</p>
</div>

<div class="methodShort" id="OnChar"><h3>OnChar</h3>
<p>检索或设置将字符添加到输入缓冲后调用的<a href="../misc/Functor.htm">函数对象</a>.</p>
<pre class="Syntax">MyFunc := InputHook.OnChar</pre>
<pre class="Syntax">InputHook.OnChar := MyFunc</pre>
<p>类型: <a href="../misc/Functor.htm">函数对象</a>或<a href="../Concepts.htm#nothing">空字符串</a>. 默认值: 空字符串.</p>
<p>函数被传递以下参数: <code>InputHook, Char</code>. <em>Char</em> 是包含一个或多个字符的字符串.</p>
<p>多个字符的存在表明在先前最后的键击中使用了一个死键, 但是这两个键不能转换为单个字符. 例如, 在一些键盘布局中 <kbd>`</kbd><kbd>e</kbd> 产生 <code>è</code>, 而 <kbd>`</kbd><kbd>z</kbd> 产生 <code>`z</code>.</p>
<p>当按下结束键时, 该函数不会被调用.</p>
</div>

<div class="methodShort" id="OnKeyDown"><h3>OnKeyDown</h3>
<p>检索或设置当按下启用通知的按键时调用的<a href="../misc/Functor.htm">函数对象</a>.</p>
<pre class="Syntax">MyFunc := InputHook.OnKeyDown</pre>
<pre class="Syntax">InputHook.OnKeyDown := MyFunc</pre>
<p>类型: <a href="../misc/Functor.htm">函数对象</a>或<a href="../Concepts.htm#nothing">空字符串</a>. 默认值: 空字符串.</p>
<p>键-按下通知必须首先由 <a href="#KeyOpt">KeyOpt</a> 或 <a href="#NotifyNonText">NotifyNonText</a> 启用.</p>
<p>函数被传递如下参数: <code>InputHook, VK, SC</code>. <em>VK</em> 和 <em>SC</em> 都是整数. 要检索按键名称(如果有), 请使用 <code>GetKeyName(Format("vk{:x}sc{:x}", VK, SC))</code>.</p>
<p>该函数作为一个新<a href="../misc/Threads.htm">线程</a>被调用, 因此使用设置(如 <a href="SendMode.htm">SendMode</a> 和 <a href="DetectHiddenWindows.htm">DetectHiddenWindows</a>) 的默认值重新开始.</p>
<p>当按下结束键时, 该函数不会被调用.</p>
</div>

<div class="methodShort" id="OnKeyUp"><h3>OnKeyUp</h3>
<p>检索或设置释放启用通知的按键时调用的<a href="../misc/Functor.htm">函数对象</a>.</p>
<pre class="Syntax">MyFunc := InputHook.OnKeyUp</pre>
<pre class="Syntax">InputHook.OnKeyUp := MyFunc</pre>
<p>类型: <a href="../misc/Functor.htm">函数对象</a>或<a href="../Concepts.htm#nothing">空字符串</a>. 默认值: 空字符串.</p>
<p>按键-释放通知必须首先由 <a href="#KeyOpt">KeyOpt</a> 或 <a href="#NotifyNonText">NotifyNonText</a> 启用. 键被认为是文本还是非文本取决于什么时候键被按下. 如果 InputHook 在没有检测到 key-down 的情况下检测到 key-up, 则认为它是非文本.</p>
<p>函数被传递如下参数: <code>InputHook, VK, SC</code>. <em>VK</em> 和 <em>SC</em> 都是整数. 要检索按键名称(如果有), 请使用 <code>GetKeyName(Format("vk{:x}sc{:x}", VK, SC))</code>.</p>
<p>该函数作为一个新<a href="../misc/Threads.htm">线程</a>, 调用, 因此使用设置(如 <a href="SendMode.htm">SendMode</a> 和 <a href="DetectHiddenWindows.htm">DetectHiddenWindows</a>) 的默认值重新开始.</p>
</div>

<h3 id="Option_Properties">选项属性</h3>
<div class="methodShort" id="BackspaceIsUndo"><h3>BackspaceIsUndo</h3>
<p>控制 <kbd>Backspace</kbd> 是否从 Input 缓冲的末尾删除最近按下的字符.</p>
<pre class="Syntax">Boolean := InputHook.BackspaceIsUndo</pre>
<pre class="Syntax">InputHook.BackspaceIsUndo := Boolean</pre>
<p>类型: <a href="../Concepts.htm#boolean">整数(布尔值)</a>. 默认值: true. 选项 <strong>B</strong> 设置该值为 false.</p>
<p>当 <kbd>Backspace</kbd> 用作 undo 时, 它被视为文本输入键. 具体来说, 是否抑制该键取决于 <a href="#VisibleText">VisibleText</a> 而不是 <a href="#VisibleNonText">VisibleNonText</a>.</p>
<p><kbd>Backspace</kbd> 与修饰符键(如 <kbd>Ctrl</kbd>) 结合使用, 则始终忽略 <kbd>Backspace</kbd>(检查的是修饰符的逻辑状态, 而不是物理状态).</p>
<p class="warning"><strong>注意:</strong> 如果输入文本是可见的(如在编辑器中) 并且使用箭头键或其他方法在其中导航, <kbd>Backspace</kbd> 仍然会删除最后一个字符, 而不是插入符号(插入点) 后面的字符.</p>
</div>

<div class="methodShort" id="CaseSensitive"><h3>CaseSensitive</h3>
<p>控制 <em>MatchList</em> 是否区分大小写.</p>
<pre class="Syntax">Boolean := InputHook.CaseSensitive</pre>
<pre class="Syntax">InputHook.CaseSensitive := Boolean</pre>
<p>类型: <a href="../Concepts.htm#boolean">整数(布尔值)</a>. 默认值: false. 选项 <strong>C</strong> 会设置该值为 true.</p>
</div>

<div class="methodShort" id="FindAnywhere"><h3>FindAnywhere</h3>
<p>控制每个匹配项是否可以是输入文本的子字符串.</p>
<pre class="Syntax">Boolean := InputHook.FindAnywhere</pre>
<pre class="Syntax">InputHook.FindAnywhere := Boolean</pre>
<p>类型: <a href="../Concepts.htm#boolean">整数(布尔值)</a>. 默认值: false. 选项 <strong>*</strong> 设置该值为 true.</p>
<p>如果为真(true), 则可以在用户键入的任何位置找到匹配(匹配可以是输入文本的子字符串). 如果为假(false), 则用户键入的所有内容必须与 <em>MatchList</em> 中的一个短语匹配. 在这两种情况下, 都必须完整输入 <em>MatchList</em> 中的一个短语.</p>
</div>

<div class="methodShort" id="MinSendLevel"><h3>MinSendLevel</h3>
<p>检索或设置要收集输入的最小<a href="SendLevel.htm">发送级别</a>.</p>
<pre class="Syntax">Level := InputHook.MinSendLevel</pre>
<pre class="Syntax">InputHook.MinSendLevel := Level</pre>
<p>类型: <a href="../Concepts.htm#numbers">整数</a>. 默认值: 0. 选项 <strong>I</strong> 设置该值为 1(或给定值).</p>
<p><em>Level</em> 应该是 0 到 101 之间的整数. 发送级别 <em>低于</em> 此值的事件将被忽略. 例如, 值 101 会忽略 <a href="Send.htm">SendEvent</a> 生成的所有输入, 而值 1 只会忽略默认发送级别(0) 的输入.</p>
<p>无论这个设置如何, <a href="Send.htm#SendInput">SendInput</a> 和 <a href="Send.htm#SendPlay">SendPlay</a> 方法总是被忽略. 除了 AutoHotkey 以外的任何其他源生成的输入都不会因为这个设置而被忽略.</p>
</div>

<div class="methodShort" id="NotifyNonText"><h3>NotifyNonText</h3>
<p>控制当按下非文本键时是否调用 <a href="#OnKeyDown">OnKeyDown</a> 和 <a href="#OnKeyUp">OnKeyUp</a> 回调.</p>
<pre class="Syntax">Boolean := InputHook.NotifyNonText</pre>
<pre class="Syntax">InputHook.NotifyNonText := Boolean</pre>
<p>类型: <a href="../Concepts.htm#boolean">整数(布尔值)</a>. 默认值: false.</p>
<p>将此设置为 true 可启用所有不产生文本的按键的通知, 如按下 <kbd>Left</kbd> 或 <kbd>Alt</kbd>+<kbd>F</kbd>. 设置此属性不会影响按键的 <a href="#KeyOpt">options</a>, 因为文本的生成取决于按下按键时活动窗口的键盘布局. </p>
<p>NotifyNonText 通过考虑先前匹配的 VK 码的 key-down 是被归类为文本还是非文本来应用 key-up 事件. 例如, 如果 NotifyNonText 为 true, 那么按下 <kbd>Ctrl</kbd>+<kbd>A</kbd> 将同时产生对 <kbd>Ctrl</kbd> 和 <kbd>A</kbd> 的 <a href="#OnKeyDown">OnKeyDown</a> 和 <a href="#OnKeyUp">OnKeyUp</a> 调用, 而按下 <kbd>A</kbd> 本身不会调用 OnKeyDown 或 OnKeyUp, 除非使用 <a href="#KeyOpt">KeyOpt</a> 来启用该键的通知.</p>
<p>有关计为生成文本的键详细信息, 请参阅 <a href="#VisibleText">VisibleText</a>.</p>
</div>

<div class="methodShort" id="Timeout"><h3>Timeout</h3>
<p>检索或设置超时值(以秒为单位).</p>
<pre class="Syntax">Seconds := InputHook.Timeout</pre>
<pre class="Syntax">InputHook.Timeout := Seconds</pre>
<p>类型: <a href="../Concepts.htm#numbers">Float</a>. 默认值: 0.0(无). 选项 <strong>T</strong> 也能设置超时值.</p>
<p>超时周期通常在调用 <a href="#Start">Start</a> 时启动, 但如果在 Input 进行中为该属性赋值, 则会重新启动. 如果在超时时间过去后 Input 仍在进行中, 则终止输入并将 <a href="#EndReason">EndReason</a> 设置为单词 Timeout.</p>
</div>

<div class="methodShort" id="VisibleNonText"><h3>VisibleNonText</h3>
<p>控制不产生文本的键或键组合是否可见(不阻止).</p>
<pre class="Syntax">Boolean := InputHook.VisibleNonText</pre>
<pre class="Syntax">InputHook.VisibleNonText := Boolean</pre>
<p>类型: <a href="../Concepts.htm#boolean">整数(布尔值)</a>. 默认值: true. 选项 <strong>V</strong> 设置该值为 true.</p>
<p>如果为真, 不产生文本的键和键组合可能触发热键或被传递到活动窗口. 如果为假, 则会阻止它们.</p>
<p>有关计为生成文本的键详细信息, 请参阅 <a href="#VisibleText">VisibleText</a>.</p>
</div>

<div class="methodShort" id="VisibleText"><h3>VisibleText</h3>
<p>控制产生文本的键或键组合是否可见(不阻止).</p>
<pre class="Syntax">Boolean := InputHook.VisibleText</pre>
<pre class="Syntax">InputHook.VisibleText := Boolean</pre>
<p>类型: <a href="../Concepts.htm#boolean">整数(布尔值)</a>. 默认值: false. 选项 <strong>V</strong> 设置该值为 true.</p>
<p>如果为真(true), 产生文本的键和键组合可以触发热键或被传递到活动窗口. 如果为假(false), 则会阻止它们.</p>
<p>导致文本被附加到输入缓冲的任何击键都被视为生成文本, 即使在其他应用程序中通常不会这样做. 例如, 如果使用 <a href="#option-m"><strong>M</strong> 选项</a>, <kbd>Ctrl</kbd>+<kbd>A</kbd> 生成文本, 而 <kbd>Esc</kbd> 生成控制字符 <code>Chr(27)</code>.</p>
<p>尽管死键通常不会立即产生效果, 但它们被视为产生文本. 按下死键也可能导致后面的键生成文本(如果只有死键的字符).</p>
<p><kbd>Backspace</kbd> 仅在<a href="#BackspaceIsUndo">作为撤销时</a>才被计为生成文本.</p>
<p><a href="../KeyList.htm#modifier">标准的修饰符键</a>和 CapsLock, NumLock 和 ScrollLock 总是可见的(不被阻止).</p>
</div>

<h2 id="EndReasons">EndReason</h2>
<p>EndReason 属性返回以下字符串之一:</p>
<table class="info">
  <tr>
    <th>字符串</th>
    <th abbr="Descr">描述</th>
  </tr>
  <tr>
    <td>Stopped</td>
    <td>Stop 方法已被调用或 Start 尚未被调用.</td>
  </tr>
  <tr>
    <td>Max</td>
    <td>输入达到允许的最大长度, 且它不匹配 <em>MatchList</em> 中的任何项.</td>
  </tr>
  <tr>
    <td>Timeout</td>
    <td>Input 超时.</td>
  </tr>
  <tr>
    <td>Match</td>
    <td>Input(输入) 匹配 <em>MatchList</em> 中的一项. <a href="#Match">Match</a> 属性包含匹配的项.</td>
  </tr>
  <tr>
    <td>EndKey</td>
    <td>
      <p><em>EndKeys</em> 中的一个被按下终止了输入. <a href="#EndKey">EndKey</a> 属性包含终止键的名称或字符, 不带大括号.</p>
    </td>
  </tr>
  <tr>
    <td></td>
    <td>如果 Input(输入) 正在进行中, EndReason 为空.</td>
  </tr>
</table>

<h2 id="Remarks">备注</h2>
<p>必须先调用 <a href="#Start">Start</a> 方法, 然后才能收集输入.</p>
<p>InputHook 设计为允许脚本的不同部分都能监视输入, 并且冲突最小. 它可以连续操作, 例如观察<a href="#ExSac">任意的单词</a>或其他模式. 它还可以临时运行, 例如收集用户输入或临时覆盖特定(或<a href="#ExKeyWaitAny">非-特定</a>) 按键而不干扰热键.</p>
<p>当 Input 正在进行时, 键盘<a href="../Hotkeys.htm">热键</a>仍然有效, 但是如果任何必需的修饰符键被抑制, 或者如果热键使用 <em>reg</em> 方法并且其后缀键被抑制, 则不能激活热键. 例如, 热键 <code>^+a::</code> <em>可能</em> 会被 InputHook 覆盖, 而热键 <code>$^+a::</code> 会优先, 除非 InputHook 抑制 <kbd>Ctrl</kbd> 或 <kbd>Shift</kbd>.</p>
<p>按键抑制(阻止) 与否取决于以下因素(按顺序):</p>
<ul>
  <li>如果 <a href="#KeyOpt-v">V 选项</a>对 VK 或 SC 有效, 则不会抑制.</li>
  <li>如果 <a href="#KeyOpt-s">S 选项</a>对 VK 或 SC 有效, 则抑制.</li>
  <li>如果按键是<a href="../KeyList.htm#modifier">标准修饰键</a>或 CapsLock, NumLock 或 ScrollLock, 则不会抑制.</li>
  <li><a href="#VisibleText">VisibleText</a> 或 <a href="#VisibleNonText">VisibleNonText</a> 是否被考虑, 具体取决于按键是否生成文本. 如果该属性为 false, 则抑制按键. 有关将哪些按键计为生成文本的详细信息, 请参阅 <a href="#VisibleText">VisibleText</a>.</li>
</ul>
<p>Input 正在进行时需要<a href="InstallKeybdHook.htm">键盘钩子</a>, 但当 Input 终止时, 如果不再需要键盘钩子, 则会自动卸载.</p>
<p>Input 正在进行时, 脚本为<a href="../Scripts.htm#persistent">自动持续运行</a>, 所以即使没有正在运行的<a href="../misc/Threads.htm">线程</a>, 它也会继续监视输入. 当输入结束时, 脚本可能会自动退出(如果没有正在运行的线程, 并且该脚本由于其他原因而不会持续运行).</p>
<p>AutoHotkey 不支持输入法编辑器(IME). 键盘钩子拦截键盘事件, 并通过使用 <a href="https://docs.microsoft.com/windows/desktop/api/winuser/nf-winuser-tounicodeex">ToUnicodeEx</a> 或 ToAsciiEx 将它们转换为文本(<a href="https://docs.microsoft.com/windows/desktop/inputdev/virtual-key-codes#vk_packet">VK_PACKET</a> 事件除外, 它封装了单个字符).</p>
<p>如果您使用多种语言或键盘布局, 则 Input 会使用活动窗口的键盘布局而不是脚本的(不论 Input 是否<a href="#vis">可见</a>).</p>
<p>尽管不够灵活, 但<a href="../Hotstrings.htm">热字串</a>更容易使用.</p>

<h2 id="comparison">InputHook vs. Input (v1)</h2>
<p>在 AutoHotkey v1.1 中, InputHook 是 Input 命令的替代品, 提供了更大的灵活性. 在 2.0 版本中删除了 Input 命令, 但下面的代码基本相同:</p>
<pre>
<em>; Input OutputVar, % Options, % EndKeys, % MatchList  ; v1</em>
ih := InputHook(Options, EndKeys, MatchList)
ih.Start()
ErrorLevel := ih.Wait()
if (ErrorLevel = "EndKey")
    ErrorLevel .= ":" ih.EndKey
OutputVar := ih.Input
</pre>
<p>Input 命令终止任何先前由它启动的 Input, 而 InputHook 允许同时<a href="#stack">多个 Input</a>.</p>
<p><em>Options</em> 解释相同, 但默认设置不同:</p>
<ul>
  <li>Input 命令将输入的长度限制为 16383, 而 InputHook 将其限制为 1023. 这可以使用 <a href="#option-l">L 选项</a>来改写, 并且没有绝对最大值.</li>
  <li>默认情况下, Input 命令会阻止文本和非文本击键, 如果使用 <a href="#vis">V 选项</a>, 则不会阻止. 相比之下, InputHook 默认只阻止文本击键(<a href="#VisibleNonText">VisibleNonText</a> 默认为 true), 因此大多数热键可以在输入正在进行时使用.</li>
</ul>
<p>Input 命令在进行时会阻塞<a href="../misc/Threads.htm">线程</a>, 而 InputHook 允许线程继续, 甚至退出(这允许中断的任何线程继续运行). 脚本可以注册一个 <a href="#OnEnd">OnEnd</a> 函数, 当输入终止时调用该函数, 而不是等待.</p>
<p>Input 命令只在输入终止后返回用户的输入, 
而 InputHook 的 <a href="#Input">Input</a> 属性允许在任何时候检索它. 脚本可以注册一个 <a href="#OnChar">OnChar</a> 函数, 以便在字符增加时调用, 而不是不断地检查 Input 属性.</p>
<p>InputHook 通过 <a href="#KeyOpt">KeyOpt</a> 方法对单个按键提供了更多控制.  这包括添加或删除结束键, 抑制或不抑制特定键, 或忽略特定键生成的文本.</p>
<p>与 Input 命令不同, InputHook 可用于检测不产生文本的键, 而 <em>不</em> 终止输入. 这是通过注册 <a href="#OnKeyDown">OnKeyDown</a> 函数和使用 <a href="#KeyOpt">KeyOpt</a> 或 <a href="#NotifyNonText">NotifyNonText</a> 来指定相关键来完成的.</p>
<p>如果 <em>MatchList</em> 中的项目导致 Input 终止, 可以参考 <a href="#Match">Match</a> 属性来确定到底是哪个匹配(当 <a href="#asterisk">* 选项</a>存在时这更有用).</p>
<p>尽管脚本可以在 Input 函数返回后查询 <a href="GetKeyState.htm">GetKeyState</a>, 但有时它无法准确反映输入终止时按下了哪些键. InputHook 的 <a href="#EndMods">EndMods</a> 属性反映了 Input 终止时修饰键的逻辑状态.</p>
<p>在向后兼容性方面有一些不同之处:</p>
<ul>
  <li>Input 命令以大写存储结束键 <kbd>A</kbd>-<kbd>Z</kbd>, 即使某些键盘布局中的一些字母是小写的. 将值传递给 <a href="Send.htm">Send</a> 会产生 Shift 的击键, 而不是普通的击键. 相比之下, InputHook 的 <a href="#EndKeys">EndKeys</a> 属性始终返回规范化的名称; 即按下该键而不按住 <kbd>Shift</kbd> 或其他修饰键时产生的字符.</li>
  <li><p>如果 <em>EndKeys</em> 中使用的键的名称对应于两个物理键共享 VK(如 <kbd>NumpadUp</kbd> 和 <kbd>Up</kbd>), 则 Input 命令通过 VK 处理主键通过 SC 处理次要键, 而 InputHook 都通过 SC 来处理. <code>{vkNN}</code> 表示可以通过 VK 来处理按键.</p>
  <p>当结束键由 VK 处理时, 两个物理键都可以终止输入. 例如, <code>{NumpadUp}</code> 将导致通过按下 <kbd>Up</kbd> 终止 Input 命令, 但是 ErrorLevel 将包含 <code>EndKey:NumpadUp</code>, 因为只考虑 VK.</p>
  <p>当结束键由 SC 处理时, Input 命令将始终为任何给定 VK 的已知辅助 SC 生成名称, 并始终为任何其他键生成 <code>sc<i>NNN</i></code>. 与之相比, InputHook 产生按键名(如果有).</p></li>
</ul>

<h2 id="Related">相关</h2>
<p><a href="KeyWait.htm">KeyWait</a>, <a href="../Hotstrings.htm">热字串</a>, <a href="InputBox.htm">InputBox</a>, <a href="InstallKeybdHook.htm">InstallKeybdHook</a>, <a href="../misc/Threads.htm">线程</a></p>

<h2 id="Examples">示例</h2>
<div class="ex" id="ExKeyWaitAny">
<p><a class="ex_number" href="#ExKeyWaitAny"></a> 等待用户按下任意一个键.</p>
<pre>
MsgBox KeyWaitAny()

<em>; 再来一遍, 但不阻止按键.</em>
MsgBox KeyWaitAny("V")

KeyWaitAny(Options:="")
{
    ih := InputHook(Options)
    if !InStr(Options, "V")
        ih.VisibleNonText := false
    ih.KeyOpt("{All}", "E")  <em>; 结束</em>
    ih.Start()
    ih.Wait()
    return ih.EndKey  <em>; 返回按键名称</em>
}
</pre>
</div>
<div class="ex" id="ExKeyWaitCombo">
<p><a class="ex_number" href="#ExKeyWaitCombo"></a> 等待任何与 Ctrl/Alt/Shift/Win 组合的按键.</p>
<pre>
MsgBox KeyWaitCombo()

KeyWaitCombo(Options:="")
{
    ih := InputHook(Options)
    if !InStr(Options, "V")
        ih.VisibleNonText := false
    ih.KeyOpt("{All}", "E")  <em>; 结束</em>
    <em>; Exclude the modifiers</em>
    ih.KeyOpt("{LCtrl}{RCtrl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}", "-E")
    ih.Start()
    ih.Wait()
    return ih.EndMods . ih.EndKey  <em>; 返回字符串, 例如 &lt;^&lt;+Esc</em>
}
</pre>
</div>
<div class="ex" id="ExSac">
<p><a class="ex_number" href="#ExSac"></a> 简单的自动完成: 一周中的任何一天. 除了字母双关外, 这是一个功能齐全的例子. 只需运行脚本并开始输入, 按 <kbd>Tab</kbd> 完成或按 <kbd>Esc</kbd> 退出.</p>
<pre>global WordList := "Monday`nTuesday`nWednesday`nThursday`nFriday`nSaturday`nSunday"

global Suffix := "", SacHook

SacHook := InputHook("V", "{Esc}")
SacHook.OnChar := SacChar
SacHook.OnKeyDown := SacKeyDown
SacHook.KeyOpt("{Backspace}", "N")
SacHook.Start()

SacChar(ih, char)  <em>; 当一个字符被添加到 SacHook.Input 时调用.</em>
{
    Suffix := ""
    if RegExMatch(ih.Input, "`nm)\w+$", prefix)
        &amp;&amp; RegExMatch(WordList, "`nmi)^" prefix[0] "\K.*", Suffix)
        Suffix := Suffix[0]
    
    if CaretGetPos(cx, cy)
        ToolTip Suffix, cx + 15, cy
    else
        ToolTip Suffix
    
    <em>; 只在显示工具提示时拦截 Tab 键.</em>
    ih.KeyOpt("{Tab}", Suffix = "" ? "-NS" : "+NS")
}

SacKeyDown(ih, vk, sc)
{
    if (vk = 8) <em>; 退格键</em>
        SacChar(ih, "")
    else if (vk = 9) <em>; Tab 键</em>
        Send "{Text}" Suffix
}
</pre>
</div>

</body>
</html>